
# 计算线上参与与线下参与关联的卡方检验值
import pandas as pd
import numpy as np

# 读取数据
df = pd.read_csv('./workspace/data.csv')

# 假定列名：线上社交使用时间、线下社交活动频次
# 请根据实际列名调整
online_col = '3、你平均每天使用线上社交软件（如微信、QQ、微博、抖音、小红书、豆瓣等）的总时长约为'
offline_col = '11、你平均每周参与线下社交活动（如班级聚会、社团活动、朋友聚餐、小组讨论等）的次数约为'

# 线上时长映射（与q1.py一致）
online_map = {
    '1小时以内': 0.5,
    '1-2小时': 1.5,
    '2-4小时': 3,
    '4-6小时': 5,
    '6小时以上': 7
}

# 线下频次映射
offline_map = {
    '1次以下': 0.5,
    '2-3次': 2.5,
    '4-5次': 4.5,
    '6次及以上': 6.5
}

# 映射数值
df['online_num'] = df[online_col].map(online_map)
df['offline_num'] = df[offline_col].map(offline_map)

# 丢弃缺失
df = df.dropna(subset=['online_num', 'offline_num'])

# 分类
def classify(row):
	if row['online_num'] >= 3:
		online = '高线上'
	else:
		online = '低线上'
	if row['offline_num'] >= 4.5:
		offline = '高线下'
	else:
		offline = '低线下'
	return online, offline

df['online_cat'], df['offline_cat'] = zip(*df.apply(classify, axis=1))

# 2x2列联表
table = pd.crosstab(df['online_cat'], df['offline_cat'])

# 保证顺序
table = table.reindex(index=['高线上', '低线上'], columns=['低线下', '高线下'], fill_value=0)

A = table.loc['高线上', '低线下']
B = table.loc['高线上', '高线下']
D = table.loc['低线上', '低线下']
E = table.loc['低线上', '高线下']

print('列联表:')
print(table)
print(f"A = {A}, B = {B}, D = {D}, E = {E}")

# 卡方值计算（Yates校正前的无偏估计，和Typst公式一致）
N = A + B + D + E
chi2 = N * (abs(A * E - B * D)) ** 2 / ((A + B) * (D + E) * (A + D) * (B + E))

print(f"卡方值 chi^2 = {chi2:.3f}")

